package cn.ms.neural.common.log;

import cn.ms.neural.common.log.impl.JdkLogFactory;
import cn.ms.neural.common.log.impl.Log4j2LogFactory;

/**
 * Log Factory
 * 
 * @author lry
 */
public abstract class LogFactory {
	
	private String logFramworkName;

	public static final String SYS_BOOT_LOG_NAME = "sys-boot";
	public static final String SYS_DEFAULT_LOG_NAME = "sys-default";
	public static final String SYS_METRICS_LOG_NAME = "sys-metrics";
	public static final String SYS_PERF_LOG_NAME = "sys-perf";
	public static final String SYS_ERROR_LOG_NAME = "sys-error";
	
	public static final String BIZ_DEFAULT_LOG_NAME = "biz-default";
	public static final String BIZ_METRICS_LOG_NAME = "biz-metrics";
	public static final String BIZ_PERF_LOG_NAME = "biz-perf";
	public static final String BIZ_ERROR_LOG_NAME = "biz-error";
	
	//$NON-NLS-System log$
	/**
	 * System default log
	 */
	public static ILog getSysDefaultLog(){
		return getCurrentLogFactory().getLog(SYS_DEFAULT_LOG_NAME);
	}
	/**
	 * System startup log
	 * 
	 * @return
	 */
	public static ILog getSysBootLog(){
		return getCurrentLogFactory().getLog(SYS_BOOT_LOG_NAME);
	}
	/**
	 * System metrics log
	 * 
	 * @return
	 */
	public static ILog getSysMetricsLog(){
		return getCurrentLogFactory().getLog(SYS_METRICS_LOG_NAME);
	}
	/**
	 * System perf log
	 * 
	 * @return
	 */
	public static ILog getSysPerfLog(){
		return getCurrentLogFactory().getLog(SYS_PERF_LOG_NAME);
	}
	/**
	 * System error log
	 * 
	 * @return
	 */
	public static ILog getSysErrorLog(){
		return getCurrentLogFactory().getLog(SYS_ERROR_LOG_NAME);
	}
	
	//$NON-NLS-Business log$
	/**
	 * Business default log
	 * 
	 * @return
	 */
	public static ILog getBizDefaultLog(){
		return getCurrentLogFactory().getLog(BIZ_DEFAULT_LOG_NAME);
	}
	/**
	 * Business metrics log
	 * 
	 * @return
	 */
	public static ILog getBizMetricsLog(){
		return getCurrentLogFactory().getLog(BIZ_METRICS_LOG_NAME);
	}
	/**
	 * Business perf log
	 * 
	 * @return
	 */
	public static ILog getBizPerfLog(){
		return getCurrentLogFactory().getLog(BIZ_PERF_LOG_NAME);
	}
	/**
	 * Business error log
	 * 
	 * @return
	 */
	public static ILog getBizErrorLog(){
		return getCurrentLogFactory().getLog(BIZ_ERROR_LOG_NAME);
	}

	
	//$NON-NLS-base$
	private static volatile LogFactory currentLogFactory;
	private static final Object lock = new Object();
	public LogFactory(String logFramworkName) {
		this.logFramworkName = logFramworkName;
	}
	
	public static LogFactory getCurrentLogFactory(){
		if(null == currentLogFactory){
			synchronized (lock) {
				if(null == currentLogFactory){
					currentLogFactory = detectLogFactory();
				}
			}
		}
		return currentLogFactory;
	}
	
	/**
	 * Custom log implementation
	 * 
	 * @param logFactory
	 */
	public static void setCurrentLogFactory(LogFactory logFactory){
		logFactory.getLog(LogFactory.class).debug("Custom Use [{}] Logger.", logFactory.logFramworkName);
		currentLogFactory = logFactory;
	}
    
	/**
	 * Get log objects
	 * 
	 * @param name
	 * @return
	 */
	public static ILog get(String name){
		return getCurrentLogFactory().getLog(name);
	}
	
	/**
	 * Get log objects
	 * 
	 * @param clazz
	 * @return
	 */
	public static ILog get(Class<?> clazz){
		return getCurrentLogFactory().getLog(clazz);
	}
	
	public static ILog get() {
		return get(new Exception().getStackTrace()[1].getClassName());
	}
	
	protected static ILog indirectGet() {
		return get(new Exception().getStackTrace()[2].getClassName());
	}
	
	/**
	 * Decision log implementation
	 * 
	 * @return
	 */
	private static LogFactory detectLogFactory(){
		LogFactory logFactory = null;
		try{
			logFactory = new Log4j2LogFactory();
			logFactory.getLog(LogFactory.class).debug("Use [{}] Logger As Default.", logFactory.logFramworkName);
		}catch(Throwable t1){
			try {
				logFactory = new JdkLogFactory();
				logFactory.getLog(LogFactory.class).debug("Use [{}] Logger As Default.", logFactory.logFramworkName);
			} catch (Throwable t2) {
			}
		}
		
		return logFactory;
	}
	
	public abstract ILog getLog(String name);
	public abstract ILog getLog(Class<?> clazz);
	
}
